#ifndef XLCOMM_BASE_BOUNDEDBLOCKINGQUEUE_H_
#define XLCOMM_BASE_BOUNDEDBLOCKINGQUEUE_H_

#include <condition_variable>
#include <mutex>

#include "boost/circular_buffer.hpp"
#include "xlcomm/define.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {

// 线程安全的有界阻塞队列（先排队、慢处理）
template <typename T>
class BoundedBlockingQueue : noncopyable {
 public:
  explicit BoundedBlockingQueue(int max_size) : queue_(max_size) {}

  // 存放一个数据到队列里。如果队列已满，则阻塞等待；完成后如果有线程等待取数据，则唤醒一个
  void Put(const T& x) {
    std::unique_lock<std::mutex> lock(mutex_);
    while (queue_.full()) {
      not_full_.wait(lock);
    }
    queue_.push_back(x);
    not_empty_.notify_one();
  }

  // 移动一个数据到队列里。如果队列已满，则阻塞等待；完成后如果有线程等待取数据，则唤醒一个
  void Put(T&& x) {
    std::unique_lock<std::mutex> lock(mutex_);
    while (queue_.full()) {
      not_full_.wait(lock);
    }
    queue_.push_back(std::move(x));
    not_empty_.notify_one();
  }

  // 从队列里取出一个数据。如果队列为空，则阻塞等待；完成后如果有线程等待放数据，则唤醒一个
  T Take() {
    std::unique_lock<std::mutex> lock(mutex_);
    while (queue_.empty()) {
      not_empty_.wait(lock);
    }
    T x = std::move(queue_.front());
    queue_.pop_front();
    not_full_.notify_one();
    return x;
  }

  // 判断队列是否为空
  bool Empty() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return queue_.empty();
  }

  // 判断队列是否已满
  bool Full() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return queue_.full();
  }

  // 获取队列已使用的大小
  size_t Size() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return queue_.size();
  }

  // 获取队列最大容量
  size_t Capacity() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return queue_.capacity();
  }

 private:
  mutable std::mutex mutex_;
  std::condition_variable not_empty_;
  std::condition_variable not_full_;
  boost::circular_buffer<T> queue_;
};

}  // namespace xlcomm

#endif  // XLCOMM_BASE_BOUNDEDBLOCKINGQUEUE_H_